package com.shutuo.callnumqixintian;

import android.util.Log;

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;

import ashy.earl.common.util.NetworkChangeHelper;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;

class Socket  {

    private OkHttpClient mOkHttpClient;
    private WebSocket mSocket;
    private String mUrl;
    private static final int STATE_IDLE = 1;
    private static final int STATE_CONNECTING = 2;
    private static final int STATE_CONNECTED = 3;
    private static final int STATE_CLOSING = 6;
    private static final int STATE_ERROR = 4;
    private static final int STATE_WAIT_NETWORK = 5;
    private  int mState = STATE_IDLE;



    private WSListener wsListener ;
    private NetworkChangeHelper mNetwork = NetworkChangeHelper.get();


    private void setState(int state,String detail) {

        if (mState==state) return;
        mState = state;
        if (wsListener!=null){
            wsListener.onStateChanged(state, detail);
        }

    }

    String stateToString(int state) {
        switch (state){
            case STATE_IDLE:
                return "idle";
            case STATE_CONNECTING:
                return "connecting";
            case STATE_CONNECTED:
                return "connected";
            case STATE_ERROR:
                return "error";
            case STATE_WAIT_NETWORK:
                return "wait-network";
            case STATE_CLOSING:
                return "closing";
            default:
                return "unknow-"+state;
        }
    }

    void setup(String url, WSListener listener) {

        mUrl = url;
        wsListener = listener;
        mNetwork.addNetworkListener(mNetworkListener);
        if (mNetwork.hasActiveNetwork()){
            connect();
            setState(STATE_CONNECTING,"");
        }else {
            setState(STATE_WAIT_NETWORK,"");
        }
    }


    private void connect() {

        mOkHttpClient = new OkHttpClient.Builder()
                            .readTimeout(3, TimeUnit.SECONDS)//设置读取超时时间
                            .writeTimeout(3, TimeUnit.SECONDS)//设置写的超时时间
                            .connectTimeout(3, TimeUnit.SECONDS)//设置连接超时时间
                            .build();
        if (mOkHttpClient!=null){

            Request request = new Request.Builder().url(mUrl).build();
            EchoWebSocketListener socketListener = new EchoWebSocketListener();
            mOkHttpClient.newWebSocket(request, socketListener);
            mOkHttpClient.dispatcher().executorService().shutdown();
        }else {
            mOkHttpClient = new OkHttpClient.Builder()
                    .readTimeout(3, TimeUnit.SECONDS)//设置读取超时时间
                    .writeTimeout(3, TimeUnit.SECONDS)//设置写的超时时间
                    .connectTimeout(3, TimeUnit.SECONDS)//设置连接超时时间
                    .build();
            Request request = new Request.Builder().url(mUrl).build();
            EchoWebSocketListener socketListener = new EchoWebSocketListener();
            mOkHttpClient.newWebSocket(request, socketListener);
            mOkHttpClient.dispatcher().executorService().shutdown();
        }
    }


    void teardown(){
        if(mOkHttpClient==null) return;
        mOkHttpClient.dispatcher().cancelAll();
        mOkHttpClient = null;
    }

    private void reConnect(){
        if(mOkHttpClient!=null){
            mOkHttpClient.dispatcher().cancelAll();
            mOkHttpClient = null;
        }
        if(mNetwork.hasActiveNetwork()){
            connect();
        }else {
            setState(STATE_WAIT_NETWORK,"");
        }
    }

    private NetworkChangeHelper.NetworkListener mNetworkListener = new NetworkChangeHelper.NetworkListener() {
        @Override
        public void onNetworkChanged(boolean hasActiveNetwork, String type, String name) {
            if (mState == STATE_IDLE) return;
            if(hasActiveNetwork){
                if(mState == STATE_ERROR || mState == STATE_WAIT_NETWORK)
                    connect();
            }else {
                if(mOkHttpClient != null) {
                        mOkHttpClient.dispatcher().cancelAll();
                    mOkHttpClient = null;
                }
                setState(STATE_WAIT_NETWORK,"");
            }
        }
    };


    private void keepAlive() {
        final String message = "{\"type\":\"heartbeat\",\"user_id\":\"heartbeat\"}";
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run(){
                mSocket.send(message);
            }
        },25000);
    }

    private  class EchoWebSocketListener extends WebSocketListener {

        @Override
        public void onOpen(WebSocket webSocket, Response response) {
            super.onOpen(webSocket, response);
            mSocket = webSocket;
            keepAlive();
            setState(STATE_CONNECTED,"");
        }

        @Override
        public void onMessage(WebSocket webSocket, ByteString bytes) {
            super.onMessage(webSocket, bytes);

        }

        @Override
        public void onMessage(WebSocket webSocket, String text) {
            super.onMessage(webSocket, text);
            wsListener.onCmd(text);
        }

        @Override
        public void onClosed(WebSocket webSocket, int code, String reason) {
            super.onClosed(webSocket, code, reason);
            setState(STATE_IDLE,code+" "+reason);
        }

        @Override
        public void onClosing(WebSocket webSocket, int code, String reason) {
            super.onClosing(webSocket, code, reason);
            setState(STATE_CLOSING,code+" "+reason);
        }

        @Override
        public void onFailure(WebSocket webSocket, Throwable t, Response response) {
            super.onFailure(webSocket, t, response);

            if(response!=null) {
                Log.d(QixintianManager.TAG, "connect failure: "+response.message());
                if (response.body() == null) {
                    throw new AssertionError();
                }
                setState(STATE_ERROR,t.getMessage()+"\n"+response.body().toString());
            }else {
                setState(STATE_ERROR,t.getMessage());
            }
            reConnect();
        }
    }



    interface WSListener {

        void onStateChanged(int state, String detail);

        void onCmd(String msg);
    }

}

